package com.kyub.spring.gears.namespace;

import com.kyub.spring.gears.model.PojoRegistryEntry;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.*;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

import java.util.Iterator;
import java.util.List;

/**
 * Bean definition parser for custom configuration schema
 */
public class PojoRegistryBeanDefinitionParser implements BeanDefinitionParser {
    private final FormFiledDelegateParser formFiledDelegate;
    private final ListFiledsParserDelegate listFiledsDelegate;

    public PojoRegistryBeanDefinitionParser() {
        formFiledDelegate = new FormFiledDelegateParser();
        listFiledsDelegate = new ListFiledsParserDelegate();
    }

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        List<Element> pojosElement = DomUtils.getChildElementsByTagName(element, "pojo");
        final Iterator<Element> elementIterator = pojosElement.iterator();
        ManagedMap map = new ManagedMap(pojosElement.size());

        map.setSource(parserContext.extractSource(element));

        final BeanDefinitionRegistry definitionRegistry = parserContext.getRegistry();
        while (elementIterator.hasNext()) {
            Element pojoElement = elementIterator.next();
            BeanDefinitionBuilder pre = BeanDefinitionBuilder.rootBeanDefinition(PojoRegistryEntry.class);


            pre.addPropertyValue("className", pojoElement.getAttribute("className"));
            final String daoRef = pojoElement.getAttribute("dao");
            if (definitionRegistry.containsBeanDefinition(daoRef)) {
                pre.addPropertyReference("dao", daoRef);

            } else throw new RuntimeException(daoRef + " not found");


            final String validatorRef = pojoElement.getAttribute("validator");
            if (StringUtils.hasText(validatorRef)) {
                if (definitionRegistry.containsBeanDefinition(validatorRef)) {
                    pre.addPropertyReference("validator", daoRef);

                } else throw new RuntimeException(validatorRef + " not found");
            }
            if (StringUtils.hasText(pojoElement.getAttribute("allowedRoles"))) {
                pre.addPropertyValue("allowedRoles", pojoElement.getAttribute("allowedRoles"));
            }
            if (StringUtils.hasText(pojoElement.getAttribute("insertableRoles"))) {
                pre.addPropertyValue("insertableRoles", pojoElement.getAttribute("insertableRoles"));
            }
            if (StringUtils.hasText(pojoElement.getAttribute("deletableRoles"))) {
                pre.addPropertyValue("deletableRoles", pojoElement.getAttribute("deletableRoles"));
            }
            if (StringUtils.hasText(pojoElement.getAttribute("editableRoles"))) {
                pre.addPropertyValue("editableRoles", pojoElement.getAttribute("editableRoles"));
            }
            if (StringUtils.hasText(pojoElement.getAttribute("insertable"))) {
                pre.addPropertyValue("insertable", pojoElement.getAttribute("insertable"));
            }
            if (StringUtils.hasText(pojoElement.getAttribute("editable"))) {
                pre.addPropertyValue("editable", pojoElement.getAttribute("editable"));
            }
            if (StringUtils.hasText(pojoElement.getAttribute("deletable"))) {
                pre.addPropertyValue("deletable", pojoElement.getAttribute("deletable"));
            }

            AbstractBeanDefinition pojoBeanDefinition = pre.getBeanDefinition();

            formFiledDelegate.parse(pojoElement, pojoBeanDefinition);


            listFiledsDelegate.parse(pojoElement, pojoBeanDefinition);


            final String keyStr = pojoElement.getAttribute("key");

            final String pojoKeyStr = "pojo_" + keyStr;

            definitionRegistry.registerBeanDefinition(pojoKeyStr, pojoBeanDefinition);

            map.put(keyStr, new RuntimeBeanReference(pojoKeyStr));


        }


        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(com.kyub.spring.gears.model.PojoRegistry.class);


        builder.setScope(BeanDefinition.SCOPE_SINGLETON);
        builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

        final RootBeanDefinition definition = (RootBeanDefinition) builder.getBeanDefinition();
        definition.setAutowireCandidate(true);
        definition.getPropertyValues().addPropertyValue(new PropertyValue("registry", map));
        definitionRegistry.registerBeanDefinition("pojoRegistry", definition);


        return definition;
    }


}
